; asmlib
; tab=4

[FORMAT "WCOFF"]
[INSTRSET "i486p"]
[BITS 32]
[FILE "asmlib.nas"]     ;file name

    GLOBAL _io_hlt, _io_cli, _io_sti, _io_stihlt
    GLOBAL _io_in8, _io_in16, _io_in32
    GLOBAL _io_out8, _io_out16, _io_out32
    GLOBAL _io_load_eflags, _io_store_eflags
    GLOBAL _load_gdtr, _load_idtr
    GLOBAL _load_cr0, _store_cr0
    GLOBAL _load_tr
    GLOBAL _asm_inthandler0c, _asm_inthandler0d
    GLOBAL _asm_inthandler20, _asm_inthandler21
    GLOBAL _asm_inthandler2c
    GLOBAL _asm_exit_app, _memtest_sub
    GLOBAL _farjmp, _farcall
    GLOBAL _asm_zic_api, _start_app
    EXTERN _inthandler0c, _inthandler0d
    EXTERN _inthandler20, _inthandler21 
    EXTERN _inthandler2c
    EXTERN _zic_api

[SECTION .text]

_io_hlt:    ;void io_hlt(void);
    hlt
    ret

_io_cli:    ;void io_cli(void);
    cli
    ret
    
_io_sti:    ;void io_sti(void);
    sti
    ret

_io_stihlt:    ;void io_stihlt(void);
    sti
    hlt
    ret

_io_in8:    ;int io_in8(int port);
    mov edx, [esp+4]    ;port
    mov eax, 0
    in al, dx
    ret

_io_in16:    ;int io_in16(int port);
    mov edx, [esp+4]    ;port
    mov eax, 0
    in ax, dx
    ret

_io_in32:    ;int io_in32(int port);
    mov edx, [esp+4]    ;port
    in eax, dx
    ret

_io_out8:    ;void io_out8(int port, int data);
    mov edx, [esp+4]    ;port
    mov al, [esp+8]     ;data
    out dx, al
    ret

_io_out16:    ;void io_out16(int port, int data);
    mov edx, [esp+4]    ;port
    mov eax, [esp+8]    ;data
    out dx, ax
    ret

_io_out32:    ;void io_out32(int port, int data);
    mov edx, [esp+4]    ;port
    mov eax, [esp+8]    ;data
    out dx, eax
    ret

_io_load_eflags:    ;int io_load_eflags(void);
    pushfd
    pop eax
    ret
_io_store_eflags:   ;void io_store_eflags(int eflags);
    mov eax, [esp+4]
    push eax
    popfd
    ret

_load_gdtr:     ;void load_gdtr(int limit, int addr);
    mov ax, [esp+4]	; limit
    mov [esp+6], ax
    lgdt [esp+6]
    ret

_load_idtr:     ;void load_idtr(int limit , int addr);
    mov ax, [esp+4]	; limit
    mov [esp+6], ax
    lidt [esp+6]
    ret

_load_cr0:      ; int load_cr0(void);
    mov eax, cr0
    ret

_store_cr0:     ; void store_cr0(int cr0);
    mov eax, [esp+4]
    mov cr0, eax
    ret

_load_tr:   ; void load_tr(int tr);
    ltr [esp+4]		;tr
    ret

_asm_inthandler0c:
    sti
    push es
    push ds
    pushad
    mov eax, esp
    push eax
    mov ax, ss
    mov ds, ax
    mov es, ax
    call _inthandler0c
    cmp eax, 0
    jne _asm_exit_app
    pop eax
    popad
    pop ds
    pop es
    add esp, 4
    iretd

_asm_inthandler0d:
    sti
    push es
    push ds
    pushad
    mov eax, esp
    push eax
    mov ax, ss
    mov ds, ax
    mov es, ax
    call _inthandler0d
    cmp eax, 0
    jne _asm_exit_app
    pop eax
    popad
    pop ds
    pop es
    add esp, 4
    iretd

_asm_inthandler20:
    push es
    push ds
    pushad
    mov eax, esp
    push eax
    mov ax, ss
    mov ds, ax
    mov es, ax
    call _inthandler20
    pop eax
    popad
    pop ds
    pop es
    iretd

_asm_inthandler21:
    push es
    push ds
    pushad
    mov eax, esp
    push eax
    mov ax, ss
    mov ds, ax
    mov es, ax
    call _inthandler21
    pop eax
    popad
    pop ds
    pop es
    iretd

_asm_inthandler2c:
    push es
    push ds
    pushad
    mov eax, esp
    push eax
    mov ax, ss
    mov ds, ax
    mov es, ax
    call _inthandler2c
    pop eax
    popad
    pop ds
    pop es
    iretd

_memtest_sub:      ; unsigned int memtest_sub(unsigned int start, unsigned int end);
    push edi
    push esi
    push ebx
    mov esi, 0xaa55aa55     ; pat0 = 0xaa55aa55;
    mov edi, 0x55aa55aa     ; pat1 = 0x55aa55aa;
    mov eax, [esp+12+4]     ; i = start;
mts_loop:
    mov ebx, eax
    add ebx, 0xffc          ; p = i + 0xffc;
    mov edx, [ebx]          ; old = *p;
    mov [ebx], esi	    ; *p = pat0;
    xor dword [ebx], 0xffffffff     ; *p ^= 0xffffffff;
    cmp edi, [ebx]          ; if (*p != pat1) goto fin;
    jne mts_fin
    xor dword [ebx], 0xffffffff     ; *p ^= 0xffffffff;
    cmp esi, [ebx]          ; if (*p != pat0) goto fin;
    jne mts_fin
    mov [ebx], edx          ; *p = old;
    add eax, 0x1000         ; i += 0x1000;
    cmp eax, [esp+12+8]     ; if (i <= end) goto mts_loop;
    jbe mts_loop
    pop ebx
    pop esi
    pop edi
    ret
mts_fin:
    mov [ebx], edx          ; *p = old;
    pop ebx
    pop esi
    pop edi
    ret

_farjmp:    ; void farjmp(int eip, int cs);
    jmp far [esp+4]
    ret

_farcall:   ; void farcall(int eip, int cs);
    call far [esp+4]
    ret

_asm_zic_api:
    sti     ; 开中断
    push ds
    push es
    pushad  ; 保存寄存器信息
    pushad  ; 向zic_apic传值
    mov ax, ss
    mov ds, ax
    mov es, ax
    call _zic_api
    cmp eax, 0
    jne _asm_exit_app
    add esp, 32
    popad
    pop es
    pop ds
    iretd   ; 此命令会自动执行sti

_asm_exit_app:
; eax为tss.esp0
    mov esp, [eax]
    mov dword [eax+4], 0
    popad
    ret


_start_app: ; void start_app(int eip, int cs, int esp, int ds, int *tss_esp0);
    pushad
    mov eax, [esp+36]   ; 应用程序用eip
    mov ecx, [esp+40]   ; 应用程序用cs
    mov edx, [esp+44]   ; 应用程序用esp
    mov ebx, [esp+48]   ; 应用程序用ds/ss
    mov ebp, [esp+52]   ; tss.esp0的地址
    mov [ebp], esp      ; 保存操作系统的esp
    mov [ebp+4], ss      ; 保存操作系统的ss
    mov es, bx
    mov ds, bx
    mov fs, bx
    mov gs, bx
; 调整栈,以免RETF跳转到应用程序
    or ecx, 3
    or ebx, 3
    push ebx    ; 应用程序用ebx
    push edx    ; 应用程序用edx
    push ecx    ; 应用程序用ecx
    push eax    ; 应用程序用eax
    retf

